<template>
  <div class="">{{ message }}</div>
</template>

<script setup lang="ts">
  import { ref } from 'vue'

  // 构造函数继承
  function Animal(name) {
    // const animal = reactive({
    //   name
    // })
    const animal = {
      name,
      test() {
        console.log(name, '555')
      }
    }

    return animal
  }

  Animal.prototype.makeSound = function () {
    console.log('Animal makes a sound')
  }

  // 子类
  function Dog(name: string, breed: string) {
    const dog = Animal(name)
    dog.breed = breed

    return dog
  }

  // 创建实例
  const myDog = Dog('Buddy', 'Golden Retriever')
  console.log(myDog.test())
  console.log(myDog.name) // 输出 "Buddy"
  console.log(myDog.breed) // 输出 "Golden Retriever"
  //   myDog.makeSound()

  //   class继承1
  class Parent {
    name: string
    constructor() {
      this.name = 'Parent'
    }
    sayHello() {
      console.log(`Hello, I'm ${this.name}`)
    }
  }

  class Child extends Parent {
    name: string
    constructor() {
      super()
      this.name = 'Child'
    }
  }

  const message = ref('')
  const child = new Child()
  console.log(child, 'child')
  child.sayHello() // 输出 "Hello, I'm Child"
  message.value = `Hello, I'm ${child.name}`

  //   class继承+ts
  //   class Parent {
  //     name: string
  //     constructor(name: string) {
  //       this.name = name
  //     }
  //     sayHi() {
  //       return `My name is ${this.name}`
  //     }
  //   }
  //   class Child extends Parent {
  //     age: string
  //     constructor(name: string, age: string) {
  //       super(name)
  //       this.age = age
  //     }
  //     getAge() {
  //       return `My age is ${this.age}`
  //     }
  //   }
  //   let c = new Child('铁锤妹妹', '18')
  //   console.log(c.sayHi())
  //   console.log(c.getAge())

  // class 继承
  class Point {
    x: number
    y: number
    constructor(x: number, y: number) {
      this.x = x
      this.y = y
    }
    toString() {
      return '(' + this.x + ', ' + this.y + ')'
    }
  }
  let d = new Point(1, 2)
  console.log(d, 'dd')
  console.log(d.toString())
  console.log(Point.prototype) // 类的所有方法都定义在类的prototype属性上面。

  // 实例属性的新写法  实例对象自身的属性都定义在类的头部
  class foo {
    name = '铁锤'
    age = 18
    x: number
    y: number
    constructor(x: number, y: number) {
      this.x = x
      this.y = y
    }
    toString() {
      return '(' + this.x + ', ' + this.y + ')'
    }
  }
  let e = new foo(5, 6)
  console.log(e.toString())
  console.log(e, 'foo')

  //   属性表达式
  let methodName = 'getArea'
  class Square {
    length = 8
    constructor(length: number) {
      this.length = length
    }
    [methodName]() {
      console.log('属性表达式')
    }
  }
  let f = new Square(7)
  console.log(Square.prototype)
  console.log(f, 'f')

  //父类私有属性和私有方法不会被子类继承，除非在父类重新再转换下
  class Foo {
    #p = 1
    getm() {
      return this.#p
    }
  }
  class Bar extends Foo {
    constructor() {
      super()

      console.log(this.getm())
    }
  }
  new Bar()

  // 静态属性和静态方法
  // 父类的静态属性和静态方法，也会被子类继承。
  class A {
    static hello() {
      console.log('hello world')
    }
  }

  class B extends A {}
  // 等同于
  // 子类没有定义 constructor，会默认添加，并且里面自动调用super()
  // class B extends A {
  //   constructor(...args) {
  //     super(...args)
  //   }
  // }
  console.log(new B(), 'B')
  B.hello()

  // 静态属性是通过浅拷贝实现继承的，对于对象来说拷贝的是一个内存地址，但是基本数据类型值就不会相互影响，是独立的内存空间
  class C {
    static foo = { n: 100 }
  }
  class D extends C {
    constructor() {
      super()
      D.foo.n--
    }
  }
  const g = new D()
  console.log(D.foo.n)
  console.log(C.foo.n)

  // 静态属性和方法 不会被new实例继承，而是直接通过类来调用，静态方法内部的 this 指向类本身，而不是类的实例
  class MyClass {
    static staticProperty = 'static Property'
    static staticMethods() {
      return 'static methods'
    }
    instanceProperty = 'instance property'
    instanceMethods() {
      return 'instance methods'
    }
  }
  console.log(MyClass, 'MyClass')
  console.log(MyClass.staticProperty)
  console.log(MyClass.staticMethods())
  const myInctance = new MyClass()
  console.log(Object.getPrototypeOf(myInctance))
  console.log(myInctance, 'myInctance')
  console.log(myInctance.instanceProperty)
  console.log(myInctance.instanceMethods())
</script>

<style lang="less" scoped></style>
